package com.qqs.distributed.advice;

import com.qqs.distributed.annotation.CacheType;
import com.qqs.distributed.annotation.LockType;
import com.qqs.distributed.cache.CacheHandler;
import com.qqs.distributed.exception.NotFoundCacheHandlerException;
import com.qqs.distributed.exception.NotFoundLockHandlerException;
import com.qqs.distributed.lock.LockHandler;
import com.qqs.distributed.lock.LockHandlerFactory;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.util.CollectionUtils;

import java.util.Set;


public class DefaultCacheInterceptor extends AbstractCacheInterceptor {
    @Override
    protected CacheAttributeWrapper determineCacheAttributeWrapper(MethodInvocation invocation) {
        CacheAttributeSource cacheAttributeSource = getCacheAttributeSource();
        CacheAttribute cacheAttribute = cacheAttributeSource.getCacheAttribute(
                invocation.getMethod(), invocation.getThis().getClass());
        if (cacheAttribute != null && cacheAttribute != CacheAttributeSource.NULL_CACHE_ATTRIBUTE) {
            CacheAttributeWrapper attributeWrapper = new CacheAttributeWrapper(cacheAttribute, invocation);
            return attributeWrapper;
        }
        return null;
    }

    @Override
    protected LockHandler determineLockHandler(CacheAttributeWrapper cacheAttributeWrapper) {
        CacheAttribute cacheAttribute = cacheAttributeWrapper.getAttribute();
        // 无锁和本地锁的特殊处理
        if (cacheAttribute.getLockType() == LockType.NO) {
            return LockHandler.NO_LOCK_HANDLER;
        }
        if (cacheAttribute.getLockType() == LockType.SYNC) {
            return LockHandler.SYNC_LOCK_HANDLER;
        }
        Set<LockHandlerFactory> lockHandlerFactorySet = getLockHandlerFactorySet();
        if (CollectionUtils.isEmpty(lockHandlerFactorySet)) {
            throw new NotFoundLockHandlerException("There are at least 1 LockHandlerFactory in the container, currently 0");
        }
        LockHandler lockHandler = doDetermineLockHandler(lockHandlerFactorySet, cacheAttributeWrapper);
        if (lockHandler == null) {
            throw new NotFoundLockHandlerException("LockHandler not found.type: " + cacheAttribute.getLockType());
        }
        return lockHandler;
    }

    @Override
    protected CacheHandler determineCacheHandler(CacheType cacheType) {
        Set<CacheHandler> cacheHandlerSet = getCacheHandlerSet();
        if (CollectionUtils.isEmpty(cacheHandlerSet)) {
            throw new NotFoundLockHandlerException("There are at least 1 CacheHandler in the container, currently 0");
        }
        CacheHandler cacheHandler = doDetermineCacheHandler(cacheHandlerSet, cacheType);
        if (cacheHandler == null) {
            throw new NotFoundCacheHandlerException("CacheHandler not found.type: " + cacheType);
        }
        return cacheHandler;
    }
    private CacheHandler doDetermineCacheHandler(Set<CacheHandler> cacheHandlerSet, CacheType cacheType) {
        for (CacheHandler cacheHandler : cacheHandlerSet) {
            if (cacheHandler.supports(cacheType)) {
                return cacheHandler;
            }
        }
        return null;
    }

    private LockHandler doDetermineLockHandler(Set<LockHandlerFactory> lockHandlerFactorySet, CacheAttributeWrapper cacheAttributeWrapper) {
        for (LockHandlerFactory lockHandlerFactory : lockHandlerFactorySet) {
            LockHandler lockHandler = lockHandlerFactory.produce(cacheAttributeWrapper);
            if (lockHandler != null) {
                return lockHandler;
            }
        }
        return null;
    }
}
